package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.rooms.absrooms.AbsMultiViewRoom;
import com.myk.game.gobangchess.signs.BadgeSign;
import com.myk.game.gobangchess.signs.ColorSign;
import com.myk.game.gobangchess.signs.GroundSign;
import com.myk.game.gobangchess.signs.LineSign;
import com.myk.game.gobangchess.signs.TitleSign;
import com.myk.game.gobangchess.utils.GridsUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 原作：《公主骑士棋》、《剑与魔法象棋》 黑先白后，轮流走棋。 【棋子走法】 （如无特殊声明，走法均可吃子） ———— 【哨兵/游侠】直前任意格； 哨兵/游侠位于任意一方底线→可横走任意格 哨兵吃子→增加马步走法 获得马步走法后，哨兵名称变更为【游侠】 ———— 【盗贼/刺客】斜前任意格；
 * 盗贼/刺客吃子或到达对方底线→获得1次瞬移使用能力 *瞬移：可传送至棋盘上任何空格，不得吃子 获得瞬移能力后，盗贼名称变更为【刺客】 ———— 【牧师】八方1格；走到友方英雄的位置时，继续朝同一方向走1格 牧师吃子→在原位置复活被牧师吃掉的棋子 ———— 【剑士】直走1到2格
 * 剑士吃子→增加斜走1格走法 获得斜走1格走法后，剑士名称变更为【剑圣】 ———— 【法师】斜走1到2格 法师吃子→在任意空格召唤1名使魔 ———— 【使魔/魔灵】向前走1格 使魔吃子→增加斜前1格走法 获得斜前1格走法后，使魔名称变更为【魔灵】 ———— 【公主】八方1格，被吃判负
 * 公主吃子：在任意空格召唤骑士，若已有骑士则使骑士升变为勇者，已有勇者则使勇者升变为英雄，已有英雄则使英雄升变为天使 【骑士】直走任意格 【勇者】直走任意格，斜走1格 【英雄】直走任意格，斜走任意格 【天使】降临至任意格
 * 即便骑士/勇者/英雄被牧师俘获，公主吃子依然可使其升变，并将其感化变回己方棋子，但公主的骑士一旦变成了天使，翅膀就硬了，公主的呼唤再也无法唤回她的天使
 */
public class PrincessKnightRoom extends AbsMultiViewRoom {

    List<Chess> chessList = new ArrayList<>();
    Chess chessSelected = null;

    List<Integer> canMoveIndex = new ArrayList<>();
    List<Integer> skillRangeIndex = new ArrayList<>();
    int[] moveArray = null;
    List<Integer> newPutIndex = new ArrayList<>();


    public PrincessKnightRoom(String roomName) {
        super(roomName, "公主骑士棋，改编自渚沙原作《剑与魔法象棋》，简化部分技能效果，优化部分棋子能力，增强游戏体验", "公主骑士棋",
            GridsUtils.createEmptyGrids(8, 8), true, true);
    }

    @Override
    public String getRuleText() {
        return "原作：《公主骑士棋》、《剑与魔法象棋》\n" +
            "黑先白后，轮流走棋。\n" +
            "【棋子走法】\n" +
            "（如无特殊声明，走法均可吃子）\n" +
            "————\n" +
            "【哨兵/游侠】直前任意格；\n" +
            "哨兵/游侠位于任意一方底线→可横走任意格\n" +
            "哨兵吃子→增加马步走法\n" +
            "获得马步走法后，哨兵名称变更为【游侠】\n" +
            "————\n" +
            "【盗贼/刺客】斜前任意格；\n" +
            "盗贼/刺客吃子/到达对方底线→获得2/1次瞬移使用能力\n" +
            "*瞬移：可传送至棋盘上任何空格，不得吃子\n" +
            "获得瞬移能力后，盗贼名称变更为【刺客】\n" +
            "————\n" +
            "【牧师】八方1格；走到友方英雄的位置时，继续朝同一方向走1格\n" +
            "牧师吃子→在原位置复活被牧师吃掉的棋子\n" +
            "————\n" +
            "【剑士】直走1到2格\n" +
            "剑士吃子→增加斜走1格走法\n" +
            "获得斜走1格走法后，剑士名称变更为【剑圣】\n" +
            "————\n" +
            "【法师】斜走1到2格\n" +
            "法师吃子→在任意空格召唤1名使魔\n" +
            "————\n" +
            "【使魔/魔灵】向前走1格\n" +
            "使魔吃子→增加斜前1格走法\n" +
            "获得斜前1格走法后，使魔名称变更为【魔灵】\n" +
            "在对方底线可以传送到任意空格\n" +
            "————\n" +
            "【公主】八方1格，被吃判负\n" +
            "公主吃子：在任意空格召唤骑士，若已有骑士则使骑士升变为勇者，已有勇者则使勇者升变为英雄，已有英雄则使英雄升变为天使\n" +
            "【骑士】直走任意格\n" +
            "【勇者】直走任意格，斜走1格\n" +
            "【英雄】直走任意格，斜走任意格\n" +
            "【天使】降临至任意格\n" +
            "即便骑士/勇者/英雄被牧师俘获，公主吃子依然可使其升变，并将其感化变回己方棋子，但公主的骑士一旦变成了天使，翅膀就硬了，公主的呼唤再也无法唤回她的天使";
    }

    @Override
    public void resetGrids() {
        step = 0;
        gameTip = "-1";
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();
        chessList.clear();
        initChess();
        chessSelected = null;
        canMoveIndex.clear();
        skillRangeIndex.clear();
        moveArray = null;
        newPutIndex.clear();
    }

    private void initChess() {
        //黑第一排
        chessList.add(new SentinelChess(1, 7, 0));
        chessList.add(new ThiefChess(1, 7, 1));
        chessList.add(new MageChess(1, 7, 2));
        chessList.add(new PriestChess(1, 7, 3));
        chessList.add(new PrincessChess(1, 7, 4));
        chessList.add(new MageChess(1, 7, 5));
        chessList.add(new ThiefChess(1, 7, 6));
        chessList.add(new SentinelChess(1, 7, 7));
        //黑第二排
        chessList.add(new FamiliarChess(1, 6, 0));
        chessList.add(new FamiliarChess(1, 6, 1));
        chessList.add(new SwordsmanChess(1, 6, 2));
        chessList.add(new FamiliarChess(1, 6, 3));
        chessList.add(new FamiliarChess(1, 6, 4));
        chessList.add(new SwordsmanChess(1, 6, 5));
        chessList.add(new FamiliarChess(1, 6, 6));
        chessList.add(new FamiliarChess(1, 6, 7));
        //白第一排
        chessList.add(new SentinelChess(2, 0, 0));
        chessList.add(new ThiefChess(2, 0, 1));
        chessList.add(new MageChess(2, 0, 2));
        chessList.add(new PriestChess(2, 0, 3));
        chessList.add(new PrincessChess(2, 0, 4));
        chessList.add(new MageChess(2, 0, 5));
        chessList.add(new ThiefChess(2, 0, 6));
        chessList.add(new SentinelChess(2, 0, 7));
        //白第二排
        chessList.add(new FamiliarChess(2, 1, 0));
        chessList.add(new FamiliarChess(2, 1, 1));
        chessList.add(new SwordsmanChess(2, 1, 2));
        chessList.add(new FamiliarChess(2, 1, 3));
        chessList.add(new FamiliarChess(2, 1, 4));
        chessList.add(new SwordsmanChess(2, 1, 5));
        chessList.add(new FamiliarChess(2, 1, 6));
        chessList.add(new FamiliarChess(2, 1, 7));
    }

    @Override
    public String getGameInfo(int view) {
        //先清空棋盘
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();
        //把每个棋子画上
        for (Chess chess : chessList) {
            chess.render(this, view);
        }
        //画一下箭头
        if (moveArray != null) {
            int start = moveArray[0], end = moveArray[1];
            if (view == 2) {
                start = getRotatedIndex(start);
                end = getRotatedIndex(end);
            }
            signList.add(new LineSign(start, end, "#66FF0000", 1));
        }
        if ((view & cur) > 0) {
            //画一下可移动范围
            for (int index : canMoveIndex) {
                if (getChessByIndex(index) != null) {
                    if (view == 2) {
                        index = getRotatedIndex(index);
                    }
                    signList.add(new ColorSign(index, "#66FFCC00"));
                } else {
                    if (view == 2) {
                        index = getRotatedIndex(index);
                    }
                    signList.add(new ColorSign(index, "#6600FF00"));
                }
            }
            //画一下可技能范围
            for (int index : skillRangeIndex) {
                if (view == 2) {
                    index = getRotatedIndex(index);
                }
                signList.add(new ColorSign(index, "#66CC00FF"));
            }
            //画一下选中了棋子
            if (chessSelected != null) {
                int index = getIndex(chessSelected.pRow, chessSelected.pCol);
                if (view == 2) {
                    index = getRotatedIndex(index);
                }
                signList.add(new GroundSign(index, "#00FFFFFF", "#FF33CC33", 2F, 0, 1));
            }
        }
        //画一下落子记号
        for (int index : newPutIndex) {
            if (view == 2) {
                index = getRotatedIndex(index);
            }
            signList.add(new GroundSign(index, "#00FFFFFF", "#66FF0000", 2, 0, 0));
        }
        return "" + step +
                "&" + cur +
                "&" + blackScore +
                "&" + whiteScore +
                "&" + gameTip +
                "&" + GridsUtils.grids2Str(curGrids) +
                "&" + getSignsInfo() +
                "&" + getCoordMode(view);
    }

    @Override
    public void doRule(int row, int col, int value, int view) {
        if (view == 2) {
            int[] pos = getRotatedPos(row, col);
            row = pos[0];
            col = pos[1];
        }
        if (chessSelected == null) {
            //看看你想走什么棋子
            Chess chessTouched = getChessByPos(row, col);
            if (chessTouched == null) {
                //没选到棋子，hhh
                return;
            }
            if (chessTouched.mSide != value) {
                //选对方的棋子干嘛？
                return;
            }
            chessSelected = chessTouched;
            canMoveIndex = chessSelected.moveRange(this);
            skillRangeIndex = chessSelected.skillRange(this);
            afterSelect();
            afterDoRule(false);
        } else if (chessSelected.needReleaseSkill) {
            chessSelected.releaseSkill(this, row, col);
            //判断是否要延续回合来使用技能
            if (chessSelected.needReleaseSkill) {
                skillRangeIndex = chessSelected.skillRange(this);
                afterDoRule(false);
                return;
            }
            chessSelected = null;
            afterReleaseSkill(row, col);
            afterDoRule(true);
        } else {
            //记录起始位置
            int startIndex = getIndex(chessSelected.pRow, chessSelected.pCol);

            //判断走子和吃子
            int[] pos = chessSelected.tryMove(this, row, col);
            if (pos == null) {
                //走子失败
                afterMoveFailed();
                afterDoRule(false);
                return;
            }

            Chess chessCaptured = getChessByPos(pos[0], pos[1]);

            //执行走子
            chessSelected.move(this, pos[0], pos[1]);
            afterMove(startIndex, getIndex(pos[0], pos[1]));
            //移除移动的子
            chessList.remove(chessSelected);
            //添加升级后的子
            chessList.add(chessSelected.afterMove(this, chessCaptured));

            if (chessCaptured != null) {
                //移除被吃的
                chessList.remove(chessCaptured);
                //判断获胜
                if (chessCaptured.mName.equals("公主")) {
                    afterWin();
                    return;
                }
            }
            //判断是否要延续回合来使用技能
            if (chessSelected.needReleaseSkill) {
                skillRangeIndex = chessSelected.skillRange(this);
                afterDoRule(false);
                return;
            }
            chessSelected = null;
            afterDoRule(true);
        }
    }

    private void afterSelect() {
    }

    private void afterMove(int startIndex, int endIndex) {
        moveArray = null;
        newPutIndex.clear();
        canMoveIndex.clear();
        skillRangeIndex.clear();
        moveArray = new int[]{startIndex, endIndex};
//        moveArray = new LineSign(startIndex, endIndex, "#66FF0000", 1);
    }

    private void afterMoveFailed() {
        chessSelected = null;
        canMoveIndex.clear();
        skillRangeIndex.clear();
    }

    private void afterReleaseSkill(int row, int col) {
        skillRangeIndex.clear();
        newPutIndex.add(getIndex(row, col));
    }

    private void afterWin() {
        if (cur == 1) {
            doOver(cur, player_black.getNickNameOrTemp() + "执黑获胜！");
        } else {
            doOver(cur, player_white.getNickNameOrTemp() + "执白获胜！");
        }
    }

    private void afterDoRule(boolean changePlayer) {
        if (changePlayer) {
            stepAdd();
            ; //增加步数避免意外重置棋盘
            if (cur == 1) {
                noticeWhiteMove();
            } else {
                noticeBlackMove();
            }
        } else {
            noticeAllRefreshGameInfo();
        }
    }

    /**
     * 根据坐标搜索棋子
     */
    private Chess getChessByPos(int row, int col) {
        for (Chess chess : chessList) {
            if (chess.pRow == row && chess.pCol == col) {
                return chess;
            }
        }
        return null;
    }

    private Map<Integer, Chess> getChessMap() {
        Map<Integer, Chess> indexes = new HashMap<>();
        for (Chess chess : chessList) {
            indexes.put(getIndex(chess.pRow, chess.pCol), chess);
        }
        return indexes;
    }

    /**
     * 根据index搜索棋子
     */
    private Chess getChessByIndex(int index) {
        int[] pos = getPositionByIndex(index);
        return getChessByPos(pos[0], pos[1]);
    }

    private abstract static class Chess {

        public boolean reborn = false;
        String mName; //棋子简名
        int mSide; //归属黑棋还是白棋 1黑  2白
        int pRow; //在棋盘上的横坐标
        int pCol; //在棋盘上的纵坐标
        boolean needReleaseSkill = false;
        List<Integer> moveRangeIndex = new ArrayList<>();
        List<Integer> skillRange = new ArrayList<>();

        public Chess(String name, int mSide, int pRow, int pCol) {
            this.mName = name;
            this.mSide = mSide;
            this.pRow = pRow;
            this.pCol = pCol;
        }

        protected int getDirection() {
            if (mSide == 1) {
                return -1;
            } else if (mSide == 2) {
                return 1;
            } else {
                return 0;
            }
        }

        protected String getColor() {
            if (mSide == 1) {
                return "#FFEE6666";
            } else if (mSide == 2) {
                return "#FF6666EE";
            } else {
                return "#FFEEEE66";
            }
        }

        protected String getBgColor() {
            return mSide == 1 ? ColorCost.DETAINED_BADGE_WHITE : ColorCost.DETAINED_BADGE_BLACK;
        }

        public void render(PrincessKnightRoom room, int view) {
            int row = pRow, col = pCol;
            if (view == 2) {
                int[] pos = room.getRotatedPos(row, col);
                row = pos[0];
                col = pos[1];
            }
            room.curGrids[row][col] = mSide; //显示棋子的底座
            int index = room.getIndex(row, col);
            room.signList.add(new TitleSign((col + 0.5f) / room.curGrids[0].length,
                (row + 0.5f) / room.curGrids.length,
                0, mName, getColor(), 0.3f));
            if (reborn) {
                room.signList.add(new BadgeSign(index, "r", 0, getColor(), getBgColor()));
            }
        }

        protected List<Integer> allEmptyGrid(PrincessKnightRoom room) {
            List<Integer> emptyGrids = new ArrayList<>();
            Map<Integer, Chess> chessMap = room.getChessMap();
            for (int i = 0; i < room.curGrids.length; i++) {
                for (int j = 0; j < room.curGrids[0].length; j++) {
                    int index = room.getIndex(i, j);
                    if (!chessMap.containsKey(index) && !moveRangeIndex.contains(index)) {
                        emptyGrids.add(index);
                    }
                }
            }
            return emptyGrids;
        }

        /**
         * 更新自己的位置，返回是否成功移动
         */
        public void move(PrincessKnightRoom room, int row, int col) {
            pRow = row;
            pCol = col;
        }

        /**
         * 尝试移动，返回移动后的位置，暂时不移动，用来判断吃子
         */
        public int[] tryMove(PrincessKnightRoom room, int row, int col) {
            if (moveRangeIndex.contains(room.getIndex(row, col))) {
                return new int[]{row, col};
            }
            return null;
        }

        public abstract List<Integer> moveRange(PrincessKnightRoom room);

        protected List<Integer> genMoveRange(PrincessKnightRoom room, int[][] dxdys, int distance) {
            for (int[] dxdy : dxdys) {
                for (int x = pRow + dxdy[0], y = pCol + dxdy[1], i = 0;
                    x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length && i < distance; x += dxdy[0], y += dxdy[1], i++) {
                    Chess chess = room.getChessByPos(x, y);
                    if (chess != null) {
                        if (chess.mSide != mSide) {
                            moveRangeIndex.add(room.getIndex(x, y));
                        }
                        break;
                    }
                    moveRangeIndex.add(room.getIndex(x, y));
                }
            }
            return moveRangeIndex;
        }

        public List<Integer> skillRange(PrincessKnightRoom room) {
            return skillRange;
        }

        public Chess afterMove(PrincessKnightRoom room, Chess captured) {
            return this;
        }

        public void releaseSkill(PrincessKnightRoom room, int row, int col) {
        }
    }

    private static class PrincessChess extends Chess {

        //公主有奴隶，但一开始没有
        Chess slave = null;

        public PrincessChess(int side, int row, int col) {
            super("公主", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}
            };
            return genMoveRange(room, dxdys, 1);
        }

        @Override
        public List<Integer> skillRange(PrincessKnightRoom room) {
            skillRange.clear();
            if (!needReleaseSkill) {
                return skillRange;
            }

            skillRange.addAll(allEmptyGrid(room));

            return skillRange;
        }

        @Override
        public Chess afterMove(PrincessKnightRoom room, Chess captured) {
            if (captured == null) {
                return this;
            }
            if (slave == null || !room.chessList.contains(slave)) {  // 如果不让唤回的话要加上 || slave.mSide != mSide
                needReleaseSkill = true;
            } else if (slave.mName.equals("骑士")) {
                room.chessList.remove(slave);
                int row = slave.pRow;
                int col = slave.pCol;
                slave = new BraveChess(mSide, row, col);
                room.chessList.add(slave);
            } else if (slave.mName.equals("勇者")) {
                room.chessList.remove(slave);
                int row = slave.pRow;
                int col = slave.pCol;
                slave = new HeroChess(mSide, row, col);
                room.chessList.add(slave);
            } else if (slave.mName.equals("英雄")) {
                room.chessList.remove(slave);
                int row = slave.pRow;
                int col = slave.pCol;
                slave = new AngelChess(mSide, row, col);
                room.chessList.add(slave);
            }
            if (slave != null) {
                slave.reborn = false;
            }
            return this;
        }

        @Override
        public void releaseSkill(PrincessKnightRoom room, int row, int col) {
            Chess chess = room.getChessByPos(row, col);
            if (chess != null) {
                return;
            }
            slave = new KnightChess(mSide, row, col);
            room.chessList.add(slave);
            needReleaseSkill = false;
        }
    }

    private static class KnightChess extends Chess {

        public KnightChess(int side, int row, int col) {
            super("骑士", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {0, -1}, {-1, 0}, {1, 0}, {0, 1}
            };

            return genMoveRange(room, dxdys, Integer.MAX_VALUE);
        }
    }

    private static class BraveChess extends Chess {

        public BraveChess(int side, int row, int col) {
            super("勇者", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {0, -1}, {-1, 0}, {1, 0}, {0, 1}
            };
            genMoveRange(room, dxdys, Integer.MAX_VALUE);

            dxdys = new int[][]{
                {-1, -1}, {1, -1}, {-1, 1}, {1, 1}
            };
            genMoveRange(room, dxdys, 1);

            return moveRangeIndex;
        }
    }

    private static class HeroChess extends Chess {

        public HeroChess(int side, int row, int col) {
            super("英雄", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {0, -1}, {-1, 0}, {1, 0}, {0, 1}
            };
            genMoveRange(room, dxdys, Integer.MAX_VALUE);

            dxdys = new int[][]{
                {-1, -1}, {1, -1}, {-1, 1}, {1, 1}
            };
            genMoveRange(room, dxdys, Integer.MAX_VALUE);

            return moveRangeIndex;
        }
    }

    private static class AngelChess extends Chess {

        public AngelChess(int side, int row, int col) {
            super("天使", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int row = room.curGrids.length;
            int col = room.curGrids[0].length;

            Map<Integer, Chess> chessMap = room.getChessMap();

            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    int index = room.getIndex(i, j);
                    Chess chess = chessMap.get(index);
                    if (chess != null && chess.mSide == mSide) {
                        continue;
                    }
                    moveRangeIndex.add(index);
                }
            }

            return moveRangeIndex;
        }
    }

    private static class FamiliarChess extends Chess {

        public FamiliarChess(int side, int row, int col) {
            super("使魔", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {getDirection(), 0}
            };
            genMoveRange(room, dxdys, 1);
            if (this.pRow + getDirection() < 0 || this.pRow + getDirection() >= room.curGrids.length) {
                moveRangeIndex.addAll(allEmptyGrid(room));
            }

            return moveRangeIndex;
        }

        @Override
        public Chess afterMove(PrincessKnightRoom room, Chess captured) {
            if (captured == null) {
                return this;
            }
            return new DemonSpiritChess(mSide, pRow, pCol);
        }
    }

    private static class DemonSpiritChess extends Chess {

        public DemonSpiritChess(int side, int row, int col) {
            super("魔灵", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {getDirection(), 0}, {getDirection(), -1}, {getDirection(), 1}
            };
            genMoveRange(room, dxdys, 1);
            if (this.pRow + getDirection() < 0 || this.pRow + getDirection() >= room.curGrids.length) {
                moveRangeIndex.addAll(allEmptyGrid(room));
            }
            return moveRangeIndex;
        }
    }

    private static class SwordsmanChess extends Chess {

        public SwordsmanChess(int side, int row, int col) {
            super("剑士", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {0, 1}, {0, -1}, {1, 0}, {-1, 0}
            };

            return genMoveRange(room, dxdys, 2);
        }

        @Override
        public Chess afterMove(PrincessKnightRoom room, Chess captured) {
            if (captured == null) {
                return this;
            }
            return new SwordSaintChess(mSide, pRow, pCol);
        }
    }

    private static class SwordSaintChess extends Chess {

        public SwordSaintChess(int side, int row, int col) {
            super("剑圣", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {0, -1}, {-1, 0}, {1, 0}, {0, 1}
            };
            genMoveRange(room, dxdys, 2);

            dxdys = new int[][]{
                {-1, -1}, {1, -1}, {-1, 1}, {1, 1}
            };
            genMoveRange(room, dxdys, 1);

            return moveRangeIndex;
        }
    }

    private static class SentinelChess extends Chess {

        SentinelChess(int side, int row, int col) {
            super("哨兵", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {getDirection(), 0}
            };
            genMoveRange(room, dxdys, Integer.MAX_VALUE);
            if (pRow == 0 || pRow == room.curGrids.length - 1) {
                dxdys = new int[][]{
                    {0, 1}, {0, -1}
                };
                genMoveRange(room, dxdys, Integer.MAX_VALUE);
            }
            return moveRangeIndex;
        }

        @Override
        public Chess afterMove(PrincessKnightRoom room, Chess captured) {
            if (captured == null) {
                return this;
            }
            return new RangerChess(mSide, pRow, pCol);
        }
    }

    private static class RangerChess extends Chess {

        RangerChess(int side, int row, int col) {
            super("游侠", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {getDirection(), 0}
            };
            genMoveRange(room, dxdys, Integer.MAX_VALUE);
            dxdys = new int[][]{
                {1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1}
            };
            genMoveRange(room, dxdys, 1);
            if (pRow == 0 || pRow == room.curGrids.length - 1) {
                dxdys = new int[][]{
                    {0, 1}, {0, -1}
                };
                genMoveRange(room, dxdys, Integer.MAX_VALUE);
            }
            return moveRangeIndex;
        }
    }

    private static class ThiefChess extends Chess {

        ThiefChess(int side, int row, int col) {
            super("盗贼", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {getDirection(), -1}, {getDirection(), 1}
            };
            return genMoveRange(room, dxdys, Integer.MAX_VALUE);
        }

        @Override
        public Chess afterMove(PrincessKnightRoom room, Chess captured) {
            if (captured != null) {
                return new AssassinChess(mSide, pRow, pCol, 2);
            }
            if (pRow + getDirection() < 0 || pRow + getDirection() >= room.curGrids.length) {
                return new AssassinChess(mSide, pRow, pCol);
            }
            return this;
        }
    }

    private static class AssassinChess extends Chess {

        int skillCount = 1;

        AssassinChess(int side, int row, int col) {
            this(side, row, col, 1);
        }

        AssassinChess(int side, int row, int col, int skillCount) {
            super("刺客", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {getDirection(), -1}, {getDirection(), 1}
            };
            return genMoveRange(room, dxdys, Integer.MAX_VALUE);
        }

        @Override
        public List<Integer> skillRange(PrincessKnightRoom room) {
            skillRange.clear();

            if (skillCount == 0) {
                return skillRange;
            }

            skillRange.addAll(allEmptyGrid(room));
            return skillRange;
        }

        @Override
        public int[] tryMove(PrincessKnightRoom room, int row, int col) {
            int index = room.getIndex(row, col);
            if (moveRangeIndex.contains(index)) {
                return new int[]{row, col};
            }
            if (skillCount > 0 && skillRange.contains(index)) {
                skillCount--;
                return new int[]{row, col};
            }
            return null;
        }

        @Override
        public Chess afterMove(PrincessKnightRoom room, Chess captured) {
            if (captured != null) {
                skillCount += 2;
            } else if (pRow + getDirection() < 0 || pRow + getDirection() >= room.curGrids.length) {
                skillCount += 1;
            }
            return this;
        }

        @Override
        public void render(PrincessKnightRoom room, int view) {
            super.render(room, view);
            int index = room.getIndex(pRow, pCol);
            if (view == 2) {
                index = room.getRotatedIndex(index);
            }
            room.signList.add(new BadgeSign(index, Integer.toString(skillCount), 2, getColor(), getBgColor()));
        }
    }

    private static class MageChess extends Chess {

        MageChess(int side, int row, int col) {
            super("法师", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {-1, -1}, {1, -1}, {-1, 1}, {1, 1}
            };
            return genMoveRange(room, dxdys, 2);
        }

        @Override
        public List<Integer> skillRange(PrincessKnightRoom room) {
            skillRange.clear();

            if (!needReleaseSkill) {
                return skillRange;
            }

            skillRange.addAll(allEmptyGrid(room));
            return skillRange;
        }

        @Override
        public Chess afterMove(PrincessKnightRoom room, Chess captured) {
            if (captured == null) {
                return this;
            }
            needReleaseSkill = true;
            return this;
        }

        @Override
        public void releaseSkill(PrincessKnightRoom room, int row, int col) {
            Chess chess = room.getChessByPos(row, col);
            if (chess != null) {
                return;
            }
            room.chessList.add(new FamiliarChess(mSide, row, col));
            needReleaseSkill = false;
        }
    }

    private static class PriestChess extends Chess {

        int[] originalPos;

        PriestChess(int side, int row, int col) {
            super("牧师", side, row, col);
        }

        @Override
        public List<Integer> moveRange(PrincessKnightRoom room) {
            moveRangeIndex.clear();
            int[][] dxdys = new int[][]{
                {0, -1}, {-1, 0}, {1, 0}, {0, 1}, {-1, -1}, {1, -1}, {-1, 1}, {1, 1}
            };
            for (int[] dxdy : dxdys) {
                for (int x = pRow + dxdy[0], y = pCol + dxdy[1]; x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length;
                    x += dxdy[0], y += dxdy[1]) {
                    Chess chess = room.getChessByPos(x, y);
                    if (chess == null || chess.mSide != mSide) {
                        //找到可以落子啦
                        moveRangeIndex.add(room.getIndex(x, y));
                        break;
                    }
                }
            }
            return moveRangeIndex;
        }

        @Override
        public void move(PrincessKnightRoom room, int row, int col) {
            originalPos = new int[]{pRow, pCol};
            super.move(room, row, col);
        }

        @Override
        public Chess afterMove(PrincessKnightRoom room, Chess captured) {
            if (captured == null) {
                return this;
            }
            captured.mSide = mSide;
            captured.pRow = originalPos[0];
            captured.pCol = originalPos[1];
            captured.reborn = true;
            room.chessList.add(captured);
            return this;
        }
    }
}
